package main

import (
	"bufio"
	"fmt"
	"io"
	"strings"
)

func fibonacci() intGen {
	a, b := 0, 1
	return func() int {
		a, b = b, a+b
		return a
	}
}

type intGen func() int  // 函数类型， 是一个类型就能实现接口~~ go语言灵活的地方
	
// 其实就是一种语法糖，前面讲过。 
// (g intGen) , 就是 g.Read() 调用。  不写这种，就是 Read(g) 调用。没有很特殊，就是普通函数
// 所以 即使是函数对象，也可以实现接口(实现方法， 方法被使用者使用，等于实现接口)
func (g intGen) Read(p []byte) (n int, err error) {
	// n: 写了多少字节， error异常
	// next 调用 g,读取下一个 斐波那契数
	next := g()
	// 控制 大于 10000停止
	if next > 10000 {
		return 0, io.EOF
	}
	// 调用Sprintf，转字符串并加入换行，存 p里
	s := fmt.Sprintf("%d\n", next)
	// 通过 NewReader 来代理写入 p的操作， 返回 n, error
	return strings.NewReader(s).Read(p)   // strings.NewReader(s) 返回一个 Reader对象， 他调用Read() 方法，将s写入p
}

func printFileContents(reader io.Reader) {
	scanner := bufio.NewScanner(reader)

	for scanner.Scan() {
		fmt.Println(scanner.Text())
	}
}


func main() {
	f := fibonacci()
	//  printFileContents 函数，将 参数 reader 定义为 io.Reader 接口类型。 所以需要 f实现了 Reader方法
	// 然后 printFileContents 函数 内部不断的操作 调用 Read方法，写入数据，然后读取。
	// 且 Read 内部实现了一个 每次将 一个 斐波那契数加入到 p 里面的功能。
	printFileContents(f)

	// 总体过程， 1. 将 f 对象作为参数传递给 printFileContents() 函数
	// 2. 内部使用 io.Reader 接口类型变量接收 f， f 实现了 Reader方法
	// 3. 内部不断的调用 next := go(), 来写入下一个 斐波那契数 供打印。


	// 难点。 1. 对 io.Reader 接口实现的理解,  2. 为一个函数类型 实现 Reade 方法（间接就是实现了io.Reader 接口）
	var a = new([5]int)
	fmt.Println(a)
}
